<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <title>Close — Space.js</title>

    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono">
    <link rel="stylesheet" href="assets/css/style.css">

    <script type="module">
        import { Interface, clearTween, ticker, tween } from '../src/index.js';

        class Close extends Interface {
            constructor() {
                super(null, 'svg');

                const size = 90;

                this.width = size;
                this.height = size;
                this.x = size / 2;
                this.y = size / 2;
                this.radius = size * 0.4;
                this.animatedIn = false;
                this.needsUpdate = false;

                this.initSVG();
            }

            initSVG() {
                this.attr({
                    width: this.width,
                    height: this.height
                });

                this.circle = new Interface(null, 'svg', 'circle');
                this.circle.attr({
                    cx: this.x,
                    cy: this.y,
                    r: this.radius
                });
                this.circle.css({
                    fill: 'none',
                    stroke: 'var(--ui-color)',
                    strokeWidth: 1.5
                });
                this.circle.start = 0;
                this.circle.offset = -0.25;
                this.circle.progress = 0;
                this.add(this.circle);

                this.icon = new Interface(null, 'svg', 'g');
                this.icon.attr({
                    transform: `translate(${(this.width - 22) / 2}, ${(this.height - 22) / 2})`
                });
                this.icon.css({
                    fill: 'none',
                    stroke: 'var(--ui-color)',
                    strokeWidth: 1.5
                });
                this.add(this.icon);

                this.line1 = new Interface(null, 'svg', 'line');
                this.line1.attr({
                    x1: 0,
                    y1: 0,
                    x2: 22,
                    y2: 22
                });
                this.line1.start = 0;
                this.line1.offset = 0;
                this.line1.progress = 0;
                this.icon.add(this.line1);

                this.line2 = new Interface(null, 'svg', 'line');
                this.line2.attr({
                    x1: 22,
                    y1: 0,
                    x2: 0,
                    y2: 22
                });
                this.line2.start = 0;
                this.line2.offset = 0;
                this.line2.progress = 0;
                this.icon.add(this.line2);
            }

            addListeners() {
                ticker.add(this.onUpdate);
            }

            removeListeners() {
                ticker.remove(this.onUpdate);
            }

            // Event handlers

            onUpdate = () => {
                if (this.needsUpdate) {
                    this.update();
                }
            };

            // Public methods

            update = () => {
                this.circle.line();
                this.line1.line();
                this.line2.line();
            };

            animateIn = () => {
                if (this.needsUpdate) {
                    return;
                }

                this.animatedIn = true;
                this.needsUpdate = true;

                this.addListeners();

                tween(this.circle, { progress: 1 }, 1000, 'easeOutCubic', () => {
                    tween(this.line1, { progress: 1 }, 400, 'easeOutCubic', () => {
                        tween(this.line2, { progress: 1 }, 400, 'easeOutCubic', () => {
                            this.removeListeners();
                            this.needsUpdate = false;
                        });
                    });
                });
            };

            animateOut = () => {
                if (this.needsUpdate) {
                    return;
                }

                this.animatedIn = false;
                this.needsUpdate = true;

                this.addListeners();

                tween(this.circle, { start: 1 }, 1000, 'easeInOutCubic', () => {
                    this.circle.start = 0;
                    this.removeListeners();
                    this.needsUpdate = false;
                }, () => {
                    this.circle.progress = 1 - this.circle.start;
                    this.line1.progress = this.circle.progress;
                    this.line2.progress = this.circle.progress;
                });
            };

            destroy = () => {
                this.removeListeners();

                clearTween(this.circle);
                clearTween(this.line1);
                clearTween(this.line2);

                return super.destroy();
            };
        }

        class App {
            static init() {
                this.initView();

                this.addListeners();
            }

            static initView() {
                this.view = new Close();
                this.view.css({
                    position: 'absolute',
                    left: '50%',
                    top: '50%',
                    marginLeft: -this.view.width / 2,
                    marginTop: -this.view.height / 2,
                    cursor: 'pointer'
                });
                document.body.appendChild(this.view.element);

                this.view.animateIn();
            }

            static addListeners() {
                this.view.element.addEventListener('click', this.onClick);
                ticker.start();
            }

            // Event handlers

            static onClick = () => {
                if (this.view.animatedIn) {
                    this.view.animateOut();
                } else {
                    this.view.animateIn();
                }
            };
        }

        App.init();
    </script>
</head>
<body>
</body>
</html>
